package project3.datasets;

import java.util.Arrays;

/**
 * Represents a discrete attribute (column with nominal values only).
 * 
 * @author Antonio
 * @author Vika
 */
public final class DiscreteAttribute extends AbstractAttribute {
	private static final long serialVersionUID = 1L;
	
	/** The possible values */
	private String[] categories;	

	/**
	 * Constructs a new DiscreteAttribute.
	 *  
	 * @param index attribute's index
	 * @param name attribute's name
	 * @param categories attribute's possible values
	 */
	public DiscreteAttribute(int index, String name, String[] categories) {
		super(index, name);
		this.categories = categories;
	}
	
	public boolean isDiscrete() {
		return true;
	}	

	/**
	 * Encodes the string passed as parameter.
	 * 
	 * @see dataset.Attribute#encode(java.lang.Object)
	 */
	public double encode(Object value) {
		if (value == null) {
			return -1;
		}
		for(int i=0;i<this.categories.length;i++) {
			if (this.categories[i].equals(value)) {
				return i;
			}
		}
		throw new IllegalArgumentException("Invalid value: " + value + " values allowed: " + this);
	}

	/**
	 * Decodes the double passed as paremeter into the string/nominal/original value.
	 * 
	 * @see dataset.Attribute#decode(double)
	 */
	public Object decode(double d) {
		if (d == Double.NaN) {
			return null;
		}
		if (d >= this.categories.length) {
			throw new IllegalArgumentException("Invalid index: " + d);
		}
		return this.categories[(int) d];		
	}

	/**
	 * @return Returns the categories.
	 */
	public String[] getCategories() {
		return categories;
	}
	
	@Override
	public String toString() {
		StringBuilder buff = new StringBuilder();
		buff.append("[DiscreteAttribute name=").append(this.name);
		buff.append(", index=").append(this.index);
		buff.append(", categories=").append(Arrays.toString(this.categories));
		buff.append(']');
		return buff.toString();
	}
	
	@Override
	public int hashCode() {
		int hash = super.hashCode();
		hash *= Arrays.hashCode(this.categories);
        return hash;
	}
	
	@Override
	public boolean equals(Object obj) {
		if (obj instanceof DiscreteAttribute) {
			DiscreteAttribute other = (DiscreteAttribute) obj;
			return 
				this.name.equals(other.name) &&
				Arrays.equals(this.categories, other.categories);
		}
		return false;
	}
}
